package com.log320.huffman;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
/**
 * Implementation of the ActionListener class used when the decompression is requested.
 * 
 */
public class DecompressActionListener implements ActionListener{
	public HuffmanFrame m_frame;

	public DecompressActionListener(HuffmanFrame myFrame){
		m_frame = myFrame;
	}
	@Override
	public void actionPerformed(ActionEvent e){
		DecompressFile();		
	}
	FileInputStream fis;
	BitOutputStream out;
	BufferedInputStream bufIS;
	BitInputStream bitIS;
	
	BinaryComposite root;
	int textLength;
/**
 * read the file from the output TextField, decompress and write it to the
 * outputTxt TextField
 */
	private void DecompressFile(){
        try {
        	File file = new File(m_frame.getOutputFilePathText());
        	fis = new FileInputStream(file);
        	bufIS = new BufferedInputStream(fis);
        	bitIS = new BitInputStream(bufIS);
        	
        	out = new BitOutputStream(new BufferedOutputStream(new FileOutputStream(m_frame.getOutputTxtFilePathText())));
        	
        	extractHeaderInfo(bitIS);
        	
        	int charValue;
        	boolean done = false;
        	int charCount = 0;
        	
        	// we decode the file
        	while (!done && charCount != textLength){
        		charValue = root.Decode(bitIS);
        		if (charValue >= 0 && charValue <= 255)
        			out.writeByte(charValue);
        		else if(charValue == -1)
        			done = true;
        		charCount++;
           	}
        	out.flush();
        }catch(FileNotFoundException ex){
        	
        } catch (IOException e) {
			e.printStackTrace();
		}
        finally {
        	//we close all the streams
        	try{
        		if (fis != null)
        			fis.close();
        		if (out != null)
        			out.close();
        		if (bufIS != null)
        			bufIS.close();
        		if (bitIS != null)
        			bitIS.close();
            }catch(FileNotFoundException ex){
            	
            }catch(IOException ioe){}
        }		
	}
/**
 * extract the information from the file header and reconstruct the codebook
 * and the tree
 * @param bitIS	the bit stream
 */
	private void extractHeaderInfo(BitInputStream bitIS)
	{
		// how many caracters are encoded
		textLength = bitIS.readInt();
		
		// how many bits are used to encode each byte
		ArrayList<BinaryCode> codeBook = new ArrayList<BinaryCode>(256);
		for(int i = 0; i < 256 ; i++){
			codeBook.add(new BinaryCode(i,bitIS.readChar()));
		}
		
		// sort by codelength first and secondly by alphabetical value
		Collections.sort(codeBook, new BinaryCodeDesiredCodeLengthComparator());
		CannonicalConverter.toCannonical(codeBook);
		
		root = new BinaryComposite(null, null);
		
		int codeLength;
		// for each code with codelength greater than zero we add a leaf in the tree
		for (BinaryCode bin : codeBook){
			LinkedList<Boolean> code = bin.getBinaryCodeListClone();
			codeLength = code.size();
			if (codeLength != 0)
				root.addLeaf(bin.getCharacter(), code, codeLength);
		}
	}
}
